/*
 * Universidade Federal Fluminense
 * Instituto de Computação
 * Prof. Pedro Braconnot Velloso
 * Sistemas Distribuídos - Turma 2011/2
 * Author: Gabriel Almeida de Oliveira
 * Description: Auxilliary Functions
 */

#include "functions.h"

packet *head = NULL, *tail = NULL;


void DieWithError(char *msg){
	perror(msg);
	exit(ERROR_DIE_WITH_ERROR);
}

char *substring(char *string, int size){
	char *ss = malloc(size);
	int i;
	for (i=0; i<size; i++)
		ss[i]=string[i];
	return ss;
}

char *calculate_hash(char* message){
	md5_state_t state;
	md5_byte_t digest[16];
	char *hex_output;
	int di;


	hex_output = (char* ) malloc( KEY_MAX_SIZE * sizeof(char) );	
	
	md5_init(&state);
	md5_append(&state, (const md5_byte_t *) message, strlen(message));
	md5_finish(&state, digest);
	for (di = 0; di < 16; ++di)
    	sprintf(hex_output + di * 2, "%02x", digest[di]);

	return hex_output;
}

unsigned int ELFHash(char* str, unsigned int len)
{
    unsigned int hash = 0;
    unsigned int x = 0;
    unsigned int i = 0;
    
    for(i = 0; i < len; str++, i++)
    {
        hash = (hash << 4) + (*str);
        if((x = hash & 0xF0000000L) != 0)
        {
            hash ^= (x >> 24);
        }
        hash &= ~x;
    }
    return hash;
}

void getContribution(char* hash, char* newHash, int numPeers)
{
    int numChar=0;
       
    if(numPeers > 1){
        numChar = (strlen(hash)/numPeers);
        strncpy(newHash, &hash[0], numChar);
	} else strcpy(newHash, hash);
    
}

void completeWithZeros(char* hash){
    int count = 0, i=0;
    
    if ( strlen(hash) < KEY_MAX_SIZE ){
        count = KEY_MAX_SIZE - strlen(hash);
        
        for( i =0; i < count ; i++){
            strcat(hash,"0");
        }
    }
}

void append_node(packet *node){
	if (head == NULL){
		head = node;
		node->prev = NULL;
	} else {
		tail->next = node;
		node->prev = tail;
	}
	tail = node;
	node->next = NULL;
}
void insert_after(packet *node, packet *after){
	node->next = after->next;
	node->prev = after;
	if (after->next != NULL)
		after->next->prev = node;
	else
		tail = node;
	after->next = node;
}
void remove_node(packet *node){
	if (node->prev == NULL)
		head = node->next;
	else
		node->prev->next = node->next;
	if (node->next == NULL)
		tail = node->prev;
	else
		node->next->prev = node->prev;
	free(node);
}
int count_nodes(){
	int i=0;
	packet *node;
	for (node = head; node!=NULL; node=node->next){
		i++;
	} 
	return i;
}

packet *search_by_address(char *ip){
	packet *node;
	for (node=head; node!=NULL; node=node->next)
		if ( !strcmp(inet_ntoa(node->address.sin_addr), ip) ) return node;
	return NULL;
}


packet *getHead(){
	return head;
}

packet *getTail(){
	return tail;
}